#include "cSimpleReportingTool.h"
#include <mxml.h>
#include "ErrorDef.h"

cSimpleReportingTool::cSimpleReportingTool(void)
{
}

cSimpleReportingTool::~cSimpleReportingTool(void)
{
}


int cSimpleReportingTool::SetDataSource(const IDataSource* Data)
{
	this->Data.push_back(Data);

	return 0;
}

int cSimpleReportingTool::SetReportFile(const char* FileName)
{
	return 0;
}

int cSimpleReportingTool::Report(IReportTarget* ReportTarget)
{
	mxml_node_t *tree;
	mxml_node_t* nodeReport;
	mxml_node_t* nodeTitle;
	mxml_node_t* nodeGroupHead;
	mxml_node_t* nodeRecord;
	mxml_node_t* nodeFooter;
	float PageScrollHeight = 0 ; // rappresent the position of page in scroll [mm]

	this->ReportTarget = ReportTarget;
	
	// load xml response
	tree= mxmlLoadString(NULL,this->XMLreport.c_str(),MXML_TEXT_CALLBACK);

	if(tree == NULL)
	{
		// error to parse xml
		return ERROR_XML_PARSE_ERROR;
	}
	/* Find the first "a" element */
	
	nodeReport = mxmlFindElement(tree,tree,"Report",NULL,NULL,MXML_DESCEND);
	nodeTitle = mxmlFindElement(tree,tree,"Title",NULL,NULL,MXML_DESCEND);
	nodeGroupHead = mxmlFindElement(tree,tree,"GroupHead",NULL,NULL,MXML_DESCEND);
	nodeRecord = mxmlFindElement(tree,tree,"Record",NULL,NULL,MXML_DESCEND);
	nodeFooter = mxmlFindElement(tree,tree,"Footer",NULL,NULL,MXML_DESCEND);
	//
	// Process GroupHead
	//
	{
		float MaxHeight=0;
		mxml_node_t* nodeElement = mxmlFindElement(nodeGroupHead,tree,"Element","Type",NULL,MXML_DESCEND);

		while(nodeElement!= NULL)
		{
			float tHeight = -1.0f;
			const char* type = mxmlElementGetAttr(nodeElement, "Type");		

			if (strcmp("staticlabel",type)==0)
			{
				printf("Render Staticlabel\n");
				RenderStaticLabel(nodeElement,PageScrollHeight,&tHeight);
			}

		
			if (strcmp("dblabel",type)==0)
			{
				printf("Render dblabel\n");
				RenderDBLabel(nodeElement,NULL,0,PageScrollHeight,&tHeight);
			}

			if(tHeight > MaxHeight)
			{
				MaxHeight = tHeight;
			}


			// next record
			nodeElement = mxmlFindElement(nodeElement,nodeGroupHead,"Element","Type",NULL,MXML_DESCEND);
		}

		PageScrollHeight += MaxHeight;
	}
	//
	// Process Record
	//
	const char* DataSourceName = mxmlElementGetAttr(nodeReport,"DataSource");
	const IDataSource* pDataSource = FindDataSourceByName(&Data,DataSourceName);
	
	int RowCount = pDataSource->GetRowCount();

	for(int i=0; i < RowCount; i++)
	{ // analize element
		float MaxHeight=0;
		mxml_node_t* nodeElement = mxmlFindElement(nodeRecord,nodeRecord,"Element","Type",NULL,MXML_DESCEND);

		while(nodeElement!= NULL)
		{
			float tHeight = -1.0f;
			const char* type = mxmlElementGetAttr(nodeElement, "Type");		

			if (strcmp("staticlabel",type)==0)
			{
				printf("Render Staticlabel\n");
				RenderStaticLabel(nodeElement,PageScrollHeight,&tHeight);
			}

		
			if (strcmp("dblabel",type)==0)
			{
				printf("Render dblabel\n");
				RenderDBLabel(nodeElement,pDataSource,i,PageScrollHeight,&tHeight);
			}

			if(tHeight > MaxHeight)
			{
				MaxHeight = tHeight;
			}


			// next record
			nodeElement = mxmlFindElement(nodeElement,nodeRecord,"Element","Type",NULL,MXML_DESCEND);
		}

		PageScrollHeight += MaxHeight;

	}
	mxmlDelete(tree);
	
	
	return 0;
}

int cSimpleReportingTool::SetReportXMLBuffer(const char* XMLbuffer)
{
	this->XMLreport = string(XMLbuffer);
	return 0;
}


void cSimpleReportingTool::DebugElement(mxml_node_t* nodeElement)
{
	if(nodeElement == NULL)
		return;
}

int cSimpleReportingTool::RenderStaticLabel(mxml_node_t* nodeElement, float StartHeight, float *Height)
{

	const char* Value;

	printf("Type: %s\n",mxmlElementGetAttr(nodeElement,"Type"));
	printf("Name: %s\n",mxmlElementGetAttr(nodeElement,"Name"));
	
	Value = mxmlElementGetAttr(nodeElement,"Value");
	if(Value == NULL)
	{
		return ERROR_MISSING_VALUE;
	}
	printf("Value: %s\n",Value);
	
	cText text(Value);

	int rc = LoadLabelStyle(nodeElement,&text);
	if(rc < 0)
	{
		return rc;
	}
	// upgrade y position
	int y = text.GetY();
	text.SetY(y + StartHeight);

	ReportTarget->DrawText(&text);
	*Height = text.MeasureTextHeight();
	
	printf("\n");
	return 0;
}

int cSimpleReportingTool::RenderDBLabel(mxml_node_t* nodeElement,const IDataSource* pDataSource, int RowN, float StartHeight, float *Height)
{
	const char* Value;
	const char* TableName;
	const char* ColumnName;
	const IDataSource *pDataSoruce = NULL;
	int ColumnNumber;

	printf("Type: %s\n",mxmlElementGetAttr(nodeElement,"Type"));
	printf("Name: %s\n",mxmlElementGetAttr(nodeElement,"Name"));
	
	TableName = mxmlElementGetAttr(nodeElement,"Table");
	if((pDataSource == NULL)&(TableName == NULL)) // if not exist Table -> use report data soruce
	{
		return ERROR_MISSING_VALUE;
	}
	printf("Table: %s\n",TableName);
	
	ColumnName = mxmlElementGetAttr(nodeElement,"Column");
	if(ColumnName == NULL)
	{
		return ERROR_MISSING_VALUE;
	}
	printf("Column: %s\n",ColumnName);
	
	// find the data source by name
	for(unsigned int i =0; i < this->Data.size();i++)
	{
		this->Data[i]->GetDataSourceName();
		const char* SourceName = this->Data[i]->GetDataSourceName();
		
		if(strcmp(SourceName, TableName) ==0)
		{
			pDataSoruce = this->Data[i];
			break;
		}
	}
	if(pDataSoruce == NULL)
	{
		return ERROR_MISSING_TABLE;
	}

	// find Column by name
	ColumnNumber = pDataSoruce->GetColumnNumber(ColumnName);
	if (ColumnNumber < 0)
	{
		return ERROR_MISSING_COLUMN;
	}

	//
	Value = pDataSoruce->GetValue(ColumnNumber,RowN);
	if( Value == NULL)
	{
		return 0;
	}
	
	printf("Value [%s][%s]:%s",TableName,ColumnName,Value);

	cText text(Value);

	int rc = LoadLabelStyle(nodeElement,&text);
	if(rc < 0)
	{
		return rc;
	}
	// upgrade y position
	int y = text.GetY();
	text.SetY(y + StartHeight);

	ReportTarget->DrawText(&text);
	*Height = text.MeasureTextHeight();
	
	printf("\n");
	return 0;
}

const IDataSource* cSimpleReportingTool::FindDataSourceByName(vector<const IDataSource*>* DataSource,const char* Name)
{
	const IDataSource *pDataSoruce = NULL;

	for(unsigned int i =0; i < DataSource->size();i++)
	{
		DataSource->at(i)->GetDataSourceName();
		const char* SourceName = DataSource->at(i)->GetDataSourceName();
		
		if(strcmp(SourceName, Name) ==0)
		{
			pDataSoruce = DataSource->at(i);
			break;
		}
	}
	
	return pDataSoruce;
	
}

// load general config for Label

int cSimpleReportingTool::LoadLabelStyle(mxml_node_t* nodeElement,cText* Text)
{
	const char* temp;
	float tempf;  // temp float
	int tempi;	// temp integer

	temp = mxmlElementGetAttr(nodeElement,"X");
	if(temp == NULL)
	{
		return ERROR_MISSING_X_Y;
	}
	tempf = atof(temp);
	printf("X: %f\n",tempf);
	Text->SetX(tempf);
	
	temp = mxmlElementGetAttr(nodeElement,"Y");
	if(temp == NULL)
	{
		return ERROR_MISSING_X_Y;
	}
	tempf = atof(temp);
	printf("Y: %f\n",tempf);
	Text->SetY(tempf);

	
	temp = mxmlElementGetAttr(nodeElement,"Size");
	if(temp == NULL)
	{
		return ERROR_MISSING_SIZE;
	}
	tempi = atoi(temp);
	printf("Size: %d\n",tempi);
	Text->SetSize(tempi);

	temp = mxmlElementGetAttr(nodeElement,"Width");
	if(temp != NULL)
	{
		tempf = atof(temp);
		printf("Width: %f\n",tempf);
		Text->SetWidth(tempf);
	}

	temp = mxmlElementGetAttr(nodeElement,"Height");
	if(temp != NULL)
	{
		tempf = atof(temp);
		printf("Height: %f\n",tempf);
		Text->SetHeight(tempf);
	}
	// text align
	temp = mxmlElementGetAttr(nodeElement,"TextAlign");
	Text->SetHorizontalAlign(eHorizontalAlign::left);
	if(temp != NULL)
	{
		if(strcmp("right",temp)==0)
			Text->SetHorizontalAlign(eHorizontalAlign::right);

		if(strcmp("center",temp)==0)
			Text->SetHorizontalAlign(eHorizontalAlign::center);

		if(strcmp("justify",temp)==0)
			Text->SetHorizontalAlign(eHorizontalAlign::justify);
	}

	// test color
	temp = mxmlElementGetAttr(nodeElement,"Color");
	if(temp != NULL)
	{
		// here check if color text is correct 
		// 6 digit hexadecimal
		Text->SetColor(temp);
	}
	return 0;
}